﻿class WsClient {
    constructor(url) {
        this.url = url
        this._waitingRemoteInvocations = new Map()
        this._commandInvocations = new Map()
        this.isOpen = false
        this.onText = text => { }
        this.onOpen = res => { }
        this.onError = res => { }
        this.connectionId = ''
    }

    connect() {
        let that = this
        wx.connectSocket({
            url: this.url
        })

        wx.onSocketOpen(res => {
            that.isOpen = true
            that.onOpen(res)
        })

        wx.onSocketError(res => {
            that.onError(res)
        })

        wx.onSocketMessage(function (res) {
            console.log("onsocketmessage: " + res.data)
            const jres = JSON.parse(res.data)
            if (jres.messageType == 0) { //text
                that.onText(jres.data)
            } else if (jres.messageType == 1) { //methodinvocation
                const invocationDes = JSON.parse(jres.data)
                if (that._commandInvocations.has(invocationDes.methodName)) {
                    const method = that._commandInvocation.get(invocationDes.methodName)
                    if (invocationDes.identifier == '') { //无标识 则不需返回值
                        try {
                            method(invocationDes.arguments || [])
                        } catch (e) {
                            console.log('on method invocation message failed', e)
                        }
                    } else {
                        let result = null;
                        let exception = null;
                        try {
                            result = method(invocationDes.arguments || [])
                        } catch (e) {
                            console.log('on method invocation message failed', e)
                            exception = e.toString()
                        }
                        that.returnMessage({
                            identifier: invocationDes.identifier,
                            result: result,
                            exception: exception
                        })
                    }
                }
            } else if (jres.messageType == 2) { //connection event
                that.connectionId = jres.data
            } else if (jres.messageType == 3) { //method return
                const invocationResult = JSON.parse(jres.data)
                if (that._waitingRemoteInvocations.has(invocationResult.identifier)) {
                    try {
                        var callback = that._waitingRemoteInvocations.get(invocationResult.identifier)
                        that._waitingRemoteInvocations.delete(invocationResult.identifier)
                        callback(invocationResult.result, invocationResult.exception)
                    }
                    catch (e) {
                        console.log('method callback failed', e)
                    }
                }
            }
        })
    }

    onCommand(commandName, command) {
        this._commandInvocations.set(commandName, command)
    }

    sendText(text) {
        wx.sendSocketMessage({
            data: JSON.stringify({
                messageType: 0,
                data: text
            })
        })
    }

    returnMessage(data) {
        this.sendMessage(3, data)
    }

    //发送消息 messageType（0 text 1 methodInvocation 2 connectionEvent 3 methodReturnValue）
    sendMessage(messageType, data) {
        wx.sendSocketMessage({
            data: JSON.stringify({
                messageType: messageType,
                data: JSON.stringify(data)
            })
        })
    }

    //调用服务端方法
    callMessage(methodName, callback, ...args) {
        let identi = uuid()
        this._waitingRemoteInvocations.set(identi, callback)
        this.sendMessage(1, {
            methodName: methodName,
            identifier: identi,
            arguments: args || []
        })
    }
}

function uuid() {
    var s = [];
    var hexDigits = "0123456789abcdef";
    for (var i = 0; i < 36; i++) {
        s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
    }
    s[14] = "4"; // bits 12-15 of the time_hi_and_version field to 0010
    s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
    s[8] = s[13] = s[18] = s[23] = "-";

    var uuid = s.join("");
    return uuid;
}